package db

import (
	"fmt"
	"time"
	"yunpan/logger"

	"go.uber.org/zap"
	"gorm.io/gorm"
)

// OnUserFileUploadFinished 文件上传完成
func OnUserFileUploadFinished(username, filehash, filename string, filesize int64, parentPath string,isOriginal bool) bool {
	userFile := UserFile{
		UserName:   username,
		FileHash:   filehash,
		FileName:   filename,
		FileSize:   filesize,
		UploadAt:   time.Now(),
		LastUpdate: time.Now(),
		ParentPath: parentPath,
		IsFolder:   false,
		DeletedAt:  nil,
		ReferenceCount: 1,
		IsOriginal: isOriginal,
	}

	result := DB.Create(&userFile)
	if result.Error != nil {
		logger.Error("插入用户文件记录失败",
			zap.String("username", username),
			zap.String("filehash", filehash),
			zap.Error(result.Error))
		return false
	}
	return true
}

// CreateUserFolder 创建文件夹
func CreateUserFolder(username, folderName, parentPath, folderHash string) error {
	// 检查同名文件夹
	var count int64
	if err := DB.Model(&UserFile{}).
		Where("user_name = ? AND parent_path = ? AND file_name = ? AND status = 0",
			username, parentPath, folderName).
		Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return fmt.Errorf("文件夹名已存在")
	}

	// 创建文件夹
	folder := UserFile{
		UserName:   username,
		FileHash:   folderHash,
		FileName:   folderName,
		UploadAt:   time.Now(),
		LastUpdate: time.Now(),
		ParentPath: parentPath,
		IsFolder:   true,
		IsOriginal: true,
	}

	return DB.Create(&folder).Error
}

// GetUserFileList 获取用户文件列表
func GetUserFileList(username, path string) ([]UserFile, error) {
	var files []UserFile
	err := DB.Where("user_name = ? AND parent_path = ? AND status = 0", username, path).
		Order("last_update desc").
		Find(&files).Error
	return files, err
}

// RenameUserFile 重命名文件
func RenameUserFile(username, filehash, newName string) error {
	var file UserFile

	// 查找文件
	if err := DB.Where("user_name = ? AND file_sha1 = ? AND status = 0",
		username, filehash).First(&file).Error; err != nil {
		return fmt.Errorf("文件不存在或无权限访问")
	}

	// 检查同名
	var count int64
	if err := DB.Model(&UserFile{}).
		Where("user_name = ? AND parent_path = ? AND file_name = ? AND file_sha1 != ? AND status = 0",
			username, file.ParentPath, newName, filehash).
		Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return fmt.Errorf("文件名已存在")
	}

	// 使用事务进行更新
	return DB.Transaction(func(tx *gorm.DB) error {
		// 更新文件名
		if err := tx.Model(&file).Updates(map[string]interface{}{
			"file_name":   newName,
			"last_update": time.Now(),
		}).Error; err != nil {
			return err
		}

		// 如果是文件夹，更新所有子文件的路径
		if file.IsFolder {
			oldPath := file.ParentPath + file.FileName + "/"
			newPath := file.ParentPath + newName + "/"

			return tx.Model(&UserFile{}).
				Where("user_name = ? AND parent_path LIKE ? AND status = 0",
					username, oldPath+"%").
				UpdateColumn("parent_path",
					gorm.Expr("REPLACE(parent_path, ?, ?)", oldPath, newPath)).
				Error
		}
		return nil
	})
}

// QueryUserFileMetas 查询用户文件元信息
func QueryUserFileMetas(username string, limit int) ([]UserFile, error) {
	var files []UserFile
	err := DB.Select("file_sha1, file_name, file_size, upload_at, last_update").
		Where("user_name = ? AND status = 0", username).
		Order("upload_at desc").
		Limit(limit).
		Find(&files).Error
	return files, err
}

func DeleteUserFile(username string, filesha1 string,filename string) (bool, error) {
	now := time.Now()
	err := DB.Transaction(func(tx *gorm.DB) error {
		// 查找文件
		var file UserFile
		if err := tx.Where("user_name = ? AND file_sha1 = ? AND file_name= ? AND status = 0",
			username, filesha1,filename).First(&file).Error; err != nil {
			return err
		}

		// 如果是文件夹，递归标记所有子文件为删除状态
		// if file.IsFolder {
		// 	if err := tx.Model(&UserFile{}).
		// 		Where("user_name = ? AND parent_path LIKE ? AND status = 0",
		// 			username, file.ParentPath+file.FileName+"/%").
		// 		Updates(map[string]interface{}{
		// 			"status":     1,
		// 			"deleted_at": now,
		// 		}).Error; err != nil {
		// 		return err
		// 	}
		// }

		// 标记文件本身为删除状态
		if err := tx.Model(&file).Updates(map[string]interface{}{
			"status":     1,
			"deleted_at": now,
		}).Error; err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return false, err
	}
	return true, nil
}

// 获取最近文件
func GetRecentFiles(username string, days int) ([]UserFile, error) {
	var files []UserFile
	deadline := time.Now().AddDate(0, 0, -days)
	err := DB.Where("user_name = ? AND status = 0 AND last_update > ?",
		username, deadline).
		Order("last_update desc").
		Find(&files).Error
	return files, err
}

// 根据文件类型获取文件
func GetFilesByType(username string, extensions []string) ([]UserFile, error) {
	var files []UserFile

	// 使用括号将扩展名条件组合起来
	extensionQuery := DB.Where("1 = 0") // 初始为 false
	for _, ext := range extensions {
		extensionQuery = extensionQuery.Or("file_name LIKE ?", "%"+ext)
	}

	// 主查询
	err := DB.Where("user_name = ? AND status = 0 AND is_folder = ?", username, false).
		Where(extensionQuery).
		Order("last_update desc").
		Find(&files).Error

	return files, err
}

// GetUserFile 获取用户文件信息
func GetUserFile(username string, fileHash string) (*UserFile, error) {
	var file UserFile
	err := DB.Where("user_name = ? AND file_sha1 = ? AND status = 1",
		username, fileHash).First(&file).Error
	if err != nil {
		return nil, err
	}
	return &file, nil
}

// CheckFileExists 检查文件是否已存在
func CheckFileExists(username string, filehash string) (bool, error) {
    // 先检查文件是否存在
    var count int64
    err := DB.Model(&UserFile{}).
        Where("file_sha1 = ? AND user_name = ? AND status = 0", filehash, username).
        Count(&count).Error

    // 如果文件存在，增加原始文件的引用计数
    if count > 0 {
        err = DB.Model(&UserFile{}).
            Where("file_sha1 = ? AND status = 0", filehash).
            Order("upload_at ASC").
            Limit(1).
            UpdateColumn("reference_count", gorm.Expr("reference_count + ?", 1)).Error
    }

    return count > 0, err
}

// GetOriginalFile 获取文件的原始上传记录
func GetOriginalFile(filehash string) (*UserFile, error) {
    var file UserFile
    err := DB.Where("file_sha1 = ? AND status = 0", filehash).
        Order("upload_at asc").  // 按上传时间正序排序，获取最早的记录
        First(&file).Error
    if err != nil {
        return nil, err
    }
    return &file, nil
}

func GetExpiredFilesBatch(expireTime time.Time, limit, offset int) ([]UserFile, error) {
    var files []UserFile
    err := DB.Where("status = 1 AND deleted_at <= ?", expireTime).
        Order("deleted_at asc").
        Limit(limit).
        Offset(offset).
        Find(&files).Error
    return files, err
}

func PermanentlyDeleteFile(fileHash string) error {
    return DB.Transaction(func(tx *gorm.DB) error {
        return tx.Where("file_hash = ?", fileHash).Delete(&UserFile{}).Error
    })
}